// "SSL connection spam" stress test

#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>

using namespace std;
using namespace boost::asio;
using namespace boost::asio::ip;

const int iterations = 100;

const char* cmdspam = "1 STARTTLS\r\n";

typedef ssl::stream<boost::asio::ip::tcp::socket> socktype;

void on_write( boost::shared_ptr< socktype > s, const boost::system::error_code& error );
void on_handshake( boost::shared_ptr< socktype > s, const boost::system::error_code& error );
void on_connect( boost::shared_ptr< socktype > s, const boost::system::error_code& error );
void on_read( boost::shared_ptr< socktype > s, const boost::system::error_code& error, int next_handshake );


vector<char> buf;

void on_write( boost::shared_ptr< socktype > s, const boost::system::error_code& error ) {
	if( error ) {
		cout << "on_write fail: " << error.message() << endl;
		return;
	}
	async_read( s->next_layer(), boost::asio::buffer(buf), boost::bind(on_read, s, boost::asio::placeholders::error, 1) );
	cout << "Write " << cmdspam;
}

void on_handshake( boost::shared_ptr< socktype > s, const boost::system::error_code& error ) {
	if( error ) {
		cout << "on_handshake fail: " << error.message() << endl;
		return;
	}
	cout << "Handshake" << endl;
}

void on_read( boost::shared_ptr< socktype > s, const boost::system::error_code& error, int next_handshake ) {
	if( error ) {
		cout << "on_read fail: " << error.message() << endl;
		return;
	}
	if( next_handshake ) {
//		s->async_handshake(boost::asio::ssl::stream_base::client, boost::bind(on_handshake, s, boost::asio::placeholders::error) );
	}else{
//		async_write( s->next_layer(), boost::asio::buffer(cmdspam),  boost::bind(on_write, s, boost::asio::placeholders::error) );
	}
	cout << "Read" << endl;
}

void on_connect( boost::shared_ptr< socktype > s, const boost::system::error_code& error ) {
	if( error ) {
		cout << "on_connect fail: " << error.message() << endl;
		return;
	}
	async_read( s->next_layer(), boost::asio::buffer(buf), boost::bind(on_read, s, boost::asio::placeholders::error, 0) );
	cout << "Connect" << endl;
}


int main(int argc, char* argv[]) {
	boost::asio::io_service io_service;
	tcp::resolver resolver(io_service);
	tcp::resolver::query query(tcp::v4(), "win61.dev.mail.ru", "143");
	tcp::resolver::iterator dest = resolver.resolve(query);

	ssl::context ctx(io_service, ssl::context::sslv23);
	ctx.set_verify_mode(ssl::context::verify_none);

	boost::thread *t = NULL;

while(1){
	cout << "Writing " << iterations <<" requests" <<endl;
	for(int i=0; i<iterations; i++) {
		boost::shared_ptr< socktype > s( new socktype(io_service, ctx) );
		s->lowest_layer().async_connect( *dest, boost::bind(on_connect, s, boost::asio::placeholders::error) );
		if( i==0 && t == NULL ) t = new boost::thread( boost::bind(&boost::asio::io_service::run, &io_service) );
	}

	t->join();
	delete t;
	t=NULL;
	io_service.reset();
}

	return 0;
}
